/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package eu.ict_omelette.mashup.adapters.pipes.database.loader;

import eu.ict_omelette.mashup.adapters.pipes.Canonical2Json;
import eu.ict_omelette.mashup.adapters.pipes.Canonical2Json;
import eu.ict_omelette.mashup.adapters.pipes.KindOfFile;
import eu.ict_omelette.mashup.canonicalmodel.CanonicalMashup;
import eu.ict_omelette.mashup.canonicalmodel.Component;
import eu.ict_omelette.mashup.canonicalmodel.Dataflow;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author guybrush
 */
public final class CompCoKnowledgeLoader {

    static final String q_create = "CREATE TABLE IF NOT EXISTS CompCo " 
                                    + "(srcComp varchar(1000), conf text, desc varchar(1000), usage int(20) DEFAULT (1), date Timestamp, "
                                    + "UpVotes int(20) DEFAULT (0), DownVotes int(20) DEFAULT (0), Tags varchar(256), "
                                    + "primary key(srcComp, conf) ) ",
                        q_multi_create = "CREATE TABLE IF NOT EXISTS MultiCompCo "
                                         + "(srcComp varchar(1000), conf text, desc varchar(1000), usage int(20) DEFAULT (1), date Timestamp, "
                                         + "UpVotes int(20) DEFAULT (0), DownVotes int(20) DEFAULT (0), Tags varchar(256), "
                                         + "primary key(srcComp, conf) ) ",
                        q_insert = "INSERT INTO CompCo (srcComp, conf, usage) VALUES ",
                        q_multi_insert = "INSERT INTO MultiCompCo (srcComp, conf, usage) VALUES ",
                        q_update = "UPDATE CompCo SET usage = ",
                        q_multi_update = "UPDATE MultiCompCo SET usage = ",
                        q_usage = "SELECT usage FROM CompCo ",
                        q_multi_usage = "SELECT usage FROM MultiCompCo ",
                        q_objs = "SELECT ComponentName FROM Template";
    private String objs_file = null;
    private KindOfFile kof = null;

    public String getObjsFile() { return objs_file; }
    public final void setObjsFile(String objs_file) { this.objs_file = objs_file; }
    public KindOfFile getKindOfFile() { return kof; }
    public void setKindOfFile(KindOfFile kof) { this.kof = kof; }

    static int index = 0, max = -1;

    public CompCoKnowledgeLoader(String objs_file, KindOfFile kof)
    { setObjsFile(objs_file); setKindOfFile(kof); }

    public void LoadFolder(String path) throws IOException, SQLException
    {
        String[] children = new File(path).list();

        if(children == null || children.length < 1)
        { System.out.println("Directory does not exists or it is empty"); System.exit(1); }

        for(int i = 0; i < children.length; i++) LoadFile(path + "/" +children[i]);
    }
    public void LoadFile(URI uri) throws IOException, SQLException { LoadFile(uri.getPath()); }
    public void LoadFile(String filepath) throws IOException, SQLException
    {
        Connection conn = null;
        Statement stat = null;
        BufferedReader reader = null;

        ArrayList<String> objs = getObjs();

        try{
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection("jdbc:sqlite:bayatest.sqlite");
            stat = conn.createStatement();
            stat.execute(q_create); stat.execute(q_multi_create);

            CanonicalMashup cm = new Canonical2Json(kof, filepath).getCanonicalMashup();

            if (objs == null || objs.size() < 1)
            {
                reader = new BufferedReader(new FileReader(new File(objs_file))); String obj = reader.readLine();
                while(obj != null) { objs.add(obj); obj = reader.readLine(); }
            }

            for (Iterator<String> it = objs.iterator(); it.hasNext();) {
                String obj = it.next();

                Boolean exit = false;

                ArrayList<Component> comps = new ArrayList<Component>();
                ArrayList<Dataflow> wires = new ArrayList<Dataflow>();
                boolean finded = false;
                for (Iterator<Component> comp_it = cm.getComponents(); comp_it.hasNext() && !exit;)
                {
                    Component comp = comp_it.next();
                    if (comp.getType().equals(obj))
                        while (addCompsAndWire(comps, wires, comp, cm.getDataFlows())) { comp = comps.get(comps.size() - 1); finded = true; }
                    if (finded) break;
                }

                if (wires.size() > 0 && comps.size() > 1)
                {
                    String conf = "{" + Canonical2Json.converteDataFlows(wires.subList(0, 1).iterator())
                               + "," + Canonical2Json.converteComponents(comps.subList(0, 2).iterator()) + "}";

                    int u = getUsage(stat, obj, conf, false);
                    if (u < 1) addRow(stat, obj, conf, false);
                    else setUsage(stat, obj, conf, u + 1, false);
                    if (wires.size() > 1)
                    {
                        conf = "{" + Canonical2Json.converteDataFlows(wires.iterator())
                               + "," + Canonical2Json.converteComponents(comps.iterator()) + "}";

                        u = getUsage(stat, obj, conf, true);
                        if (u < 1) addRow(stat, obj, conf, true); 
                        else setUsage(stat, obj, conf, u + 1, true);
                    }
                }
            }
        }catch(Exception e){ System.out.println(e.getMessage() + " in file: " + filepath); }
        finally
        {
            if (reader != null) reader.close();
            if (stat != null) stat.close();
            if (conn != null) conn.close();
        }
    }
    static private Boolean addCompsAndWire(ArrayList<Component> comps, ArrayList<Dataflow> wires, Component comp, Iterator<Dataflow> it)
    {
        Boolean exit = false;
        for (Iterator<Dataflow> wire_it = it; wire_it.hasNext();) {
            Dataflow wire = wire_it.next();

            if (wire.getFromComponent().getId().equals(comp.getId()) && !wire.getFromComponent().getId().equals(wire.getToComponent().getId()))
            { if (comps.size() < 1 || !comps.get(comps.size() - 1).equals(comp)) comps.add(comp); comps.add(wire.getToComponent()); exit = true; }

            if (exit) { wires.add(wire); break; }
        }

        return exit;
    }
    static private ArrayList<String> getObjs() throws SQLException
    {
        ArrayList<String> ret = new ArrayList<String>();
        Connection conn = null;
        Statement stat = null;

        try{
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection("jdbc:sqlite:bayatest.sqlite");
            stat = conn.createStatement();

            ResultSet res = stat.executeQuery(q_objs);

            while(res.next())
                ret.add(res.getString(1));

        }catch(Exception e){ e.printStackTrace(); }
        finally
        {
            if (stat != null) stat.close();
            if (conn != null) conn.close();
        }

        return ret;
    }
    static private String getDefWhereStmt(String src, String conf)
    { return " WHERE srcComp = '" + src.replaceAll("'", "&#039;") + "' AND conf = '" + conf.replaceAll("'", "&#039;") + "'"; }
    static private void addRow(Statement stmt, String src, String conf, boolean multi) throws SQLException
    { 
        String insert = multi ? q_multi_insert : q_insert;
        stmt.execute(insert + "('" + src.replaceAll("'", "&#039;") + "','" + conf.replaceAll("'", "&#039;") + "',1)");
    }
    static private void incUsage(Statement stmt, String src, String conf, boolean multi) throws SQLException
    { setUsage(stmt, src, conf, (getUsage(stmt, src, conf, multi) + 1), multi); }
    static private void setUsage(Statement stmt, String src, String conf, Integer usage, boolean multi) throws SQLException
    {
        String update = multi ? q_multi_update : q_update;
        stmt.executeUpdate(update + "'" + String.valueOf(usage) + "'" + getDefWhereStmt(src, conf));
    }
    static private Integer getUsage(Statement stmt, String src, String conf, boolean multi) throws SQLException
    {
        String qry = null;
        try
        {
            String usage = multi ? q_multi_usage : q_usage;
            qry = usage + getDefWhereStmt(src, conf);
            ResultSet res = stmt.executeQuery(qry);
            if (res.next())
                return res.getInt(1); return 0;
        }catch(SQLException e) { 
            if (qry != null)  System.out.println("Error in query usage:\n" + (qry = (qry = qry.split("conf = '")[1]).substring(0, qry.length() - 1))
                                                 + "\nContain \"'\"? " + qry.contains("'"));
            else throw e;
        }

        return 0;


        /*
         SELECT usage
         FROM CompCo
         WHERE srcComp = 'regex'
           AND conf = '{"wires":[{"id":"_w1","src":{"id":"regex","moduleid":"regex"},"tgt":{"id":"loop","moduleid":"loop"}}],"modules":[{"type":"regex","id":"regex","conf":{"RULE":[{"field":{"value":"title","type":"text"},"match":{"value":"","type":"text"},"replace":{"value":"$1","type":"text"},"globalmatch":{"value":"1","type":"text"},"singlelinematch":{"value":"2","type":"text"},"multilinematch":{"value":"4","type":"text"},"casematch":{"value":"8","type":"text"}},{"field":{"value":"link","type":"text"},"match":{"value":"","type":"text"},"replace":{"value":"$1","type":"text"},"globalmatch":{"value":"1","type":"text"},"singlelinematch":{"value":"2","type":"text"},"multilinematch":{"value":"4","type":"text"},"casematch":{"value":"8","type":"text"}},{"field":{"value":"tag","type":"text"},"match":{"value":"","type":"text"},"replace":{"value":"$1","type":"text"},"globalmatch":{"value":"1","type":"text"},"singlelinematch":{"value":"2","type":"text"},"multilinematch":{"value":"4","type":"text"},"casematch":{"value":"8","type":"text"}},{"field":{"value":"description","type":"text"},"match":{"value":"(<em>.*?</em>)","type":"text"},"replace":{"value":"","type":"text"},"globalmatch":{"value":"1","type":"text"},"singlelinematch":{"value":"2","type":"text"},"multilinematch":{"value":"4","type":"text"},"casematch":{"value":"8","type":"text"}},{"field":{"value":"description","type":"text"},"match":{"value":"(<p class='title'>.*?</p>)","type":"text"},"replace":{"value":"","type":"text"},"globalmatch":{"value":"1","type":"text"},"singlelinematch":{"value":"2","type":"text"},"multilinematch":{"value":"4","type":"text"},"casematch":{"value":"8","type":"text"}}]}},{"type":"loop","id":"loop","conf":{"embed":{"value":{"type":"strconcat","id":"strconcat","conf":{"part":[{"value":"http://www.wegame.com/static/flash/player2.swf?tag=","type":"text"},{"value":"tag","type":"text"}]}},"type":"module"},"with":{"value":"","type":"text"},"emit_part":{"value":"","type":"text"},"mode":{"value":"","type":"text"},"assign_part":{"value":"","type":"text"},"assign_to":{"value":"","type":"text"}}}]}'
        */
    }
}

